package core

import "kumachan/standalone/ctn"


func Lens1FromRecord(object Object, index int) Object {
	return ToObject(lens1fromRecord(object, index))
}
func Lens2FromUnion(object Object, index int) Object {
	return ToObject(lens2fromUnion(ctn.Just(object), index))
}
func Lens2FromInterface(object Object, t *DispatchTable) Object {
	return ToObject(lens2fromInterface(ctn.Just(object), t))
}
func Lens1FromRecordLens1(object Object, index int) Object {
	var ab = FromObject[lens1](object)
	return ToObject(lens1compose1(ab, func(b Object) lens1 {
		return lens1fromRecord(b, index)
	}))
}
func Lens2FromUnionLens1(object Object, index int) Object {
	var ab = FromObject[lens1](object)
	return ToObject(lens1compose2(ab, func(b Object) lens2 {
		return lens2fromUnion(ctn.Just(b), index)
	}))
}
func Lens2FromUnionLens2(object Object, index int) Object {
	var ab = FromObject[lens2](object)
	return ToObject(lens2compose(ab, func(opt_b ctn.Optional[Object]) lens2 {
		return lens2fromUnion(opt_b, index)
	}))
}
func Lens2FromInterfaceLens1(object Object, t *DispatchTable) Object {
	var ab = FromObject[lens1](object)
	return ToObject(lens1compose2(ab, func(b Object) lens2 {
		return lens2fromInterface(ctn.Just(b), t)
	}))
}
func Lens2FromInterfaceLens2(object Object, t *DispatchTable) Object {
	var ab = FromObject[lens2](object)
	return ToObject(lens2compose(ab, func(opt_b ctn.Optional[Object]) lens2 {
		return lens2fromInterface(opt_b, t)
	}))
}

func lens1fromRecord(object Object, index int) lens1 {
	var r = (*object).(Record)
	var objects = r.Objects
	if !(index < len(objects)) {
		panic("invalid argument")
	}
	return lens1 {
		value:  objects[index],
		update: func(new_object Object) Object {
			var new_objects = make([] Object, len(objects))
			new_objects[index] = new_object
			var o = ObjectImpl(Record { new_objects })
			return &o
		},
	}
}
func lens2fromUnion(opt_object ctn.Optional[Object], index int) lens2 {
	var value = ctn.Null[Object]()
	if object, ok := opt_object.Value(); ok {
		var u = (*object).(Union)
		if u.Index == index {
			value = ctn.Just(u.Object)
		}
	}
	return lens2 {
		value:  value,
		update: func(new_object Object) Object {
			var o = ObjectImpl(Union {
				Index:  index,
				Object: new_object,
			})
			return &o
		},
	}
}
func lens2fromInterface(opt_object ctn.Optional[Object], t *DispatchTable) lens2 {
	var value = ctn.Null[Object]()
	if object, ok := opt_object.Value(); ok {
		var u = (*object).(Interface)
		if u.DispatchTable == t {
			value = ctn.Just(u.UnderlyingObject)
		}
	}
	return lens2 {
		value:  value,
		update: func(new_object Object) Object {
			var o = ObjectImpl(Interface {
				UnderlyingObject: new_object,
				DispatchTable:    t,
			})
			return &o
		},
	}
}
func lens1compose1(ab lens1, f func(Object)(lens1)) lens1 {
	return lens1 {
		value:  f(ab.value).value,
		update: func(c Object) Object {
			return ab.update(f(ab.value).update(c))
		},
	}
}
func lens1compose2(ab lens1, f func(Object)(lens2)) lens2 {
	return lens2 {
		value:  f(ab.value).value,
		update: func(c Object) Object {
			return ab.update(f(ab.value).update(c))
		},
	}
}
func lens2compose(ab lens2, f func(ctn.Optional[Object])(lens2)) lens2 {
	return lens2 {
		value:  f(ab.value).value,
		update: func(c Object) Object {
			return ab.update(f(ab.value).update(c))
		},
	}
}


